home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC Graphics Unleashed
/
PC Graphics Unleashed.iso
/
ch06
/
ufo.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-07-22
|
37KB
|
1,047 lines
#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
#include<fcntl.h>
#include<io.h>
#include<math.h>
#include<vsa.h>
#include<vsa_font.h>
#include <sys\types.h>
#include<sys\stat.h>
#ifndef _MSC_VER
/*..... This is for Borland C Only ! .....*/
extern unsigned _stklen = 10000;
#endif
#define FAST_RGB 0 /* Set to 1 for fast, lower quality images */
/*.............................................................*/
/* Function Prototypes go here. */
/*.............................................................*/
void introduction(void);
void azure_sky(unsigned char *,int,int);
void wipe_sky(unsigned char *,int,int);
void shrink_city(unsigned char *,int,int);
void merge_city(unsigned char *,int,int);
void merge_azure(unsigned char *,unsigned char *,int,int);
void shrink_saucer(unsigned char *,int,int);
void merge_saucer(unsigned char *,int,int);
void add_shadow(unsigned char *,int,int);
void add_beam(unsigned char *,int,int);
void get_dithered_row(int,int,unsigned char *,
unsigned char *);
int crack_rgb(unsigned char *,int *,int *,int *,float *,
float *,float *);
long read_tga_header(int,int *,int *,int *,int *);
int write_tga_header(int,int,int,int);
void true_color_lut(void);
void process_step(unsigned char *,unsigned char *,
int,int,int);
float color_mag(float,float,float);
float color_error(float,float,float,float,float,float);
float hue_error(float,float,float,float,float,float);
void bummer(char *);
void text_update(char *,int);
void frame(void);
void ellipse(int,int);
void soft_edge(unsigned char *,int,int);
/*.............................................................*/
/* External Parameters declared here. */
/*.............................................................*/
unsigned char dither[4][64]={
{
1 },
{
1, 3,
4, 2 },
{
1, 9, 3, 11,
13, 5, 15, 7,
4, 12, 2, 10,
16, 8, 14, 6 },
{
1, 33, 9, 41, 3, 35, 11, 43,
49, 17, 57, 25, 51, 19, 59, 27,
13, 45, 5, 37, 15, 47, 7, 39,
61, 29, 53, 21, 63, 31, 55, 23,
4, 36, 12, 44, 2, 34, 10, 42,
52, 20, 60, 28, 50, 18, 58, 26,
16, 48, 8, 40, 14, 46, 6, 38,
64, 32, 56, 24, 62, 30, 54, 22 },
};
char file_i1[9][30]={
{""},
{"mountain.tga"},
{"city.tga"},
{"wiped.tga"},
{"withcity.tga"},
{"saucer.tga"},
{"withsky.tga"},
{"withsauc.tga"},
{"withshad.tga"},
};
char file_i2[9][30]={
{""},
{""},
{""},
{""},
{"sky.tga"},
{""},
{""},
{""},
{""},
};
char file_o[9][30]={
{"sky.tga"},
{"wiped.tga"},
{""},
{"withcity.tga"},
{"withsky.tga"},
{""},
{"withsauc.tga"},
{"withshad.tga"},
{"ufo.tga"},
};
unsigned char far image[16384];
unsigned far big_image[16384];
void main()
{
int j,width,height,type,orient;
int file_i1_handle,file_i2_handle,file_o_handle;
int jstrt,jend,jstep,step;
unsigned char rgb_1[3072],rgb_2[3072];
char text[100];
width = 640;
height = 480;
orient = 0;
introduction();
/*.............................................................*/
/* Set highest video resolution available. */
/*.............................................................*/
if(vsa_init(0x101) != 0) /* 640 x 480 x 256 */
if(vsa_init(0x100) != 0) /* 640 x 400 x 256 */
{
printf("Can't set VESA video mode\n");
printf("Is VESA BIOS Extension TSR loaded?\n");
return;
}
true_color_lut();
for(step=0;step<9;step++)
{
/*.............................................................*/
/* Open the TARGA file(s) and get header info. When two files*/
/* being opened simultaneously, they must be same type, size, */
/* and orientation! */
/*.............................................................*/
if(file_i1[step][0])
{
if((file_i1_handle = open(file_i1[step],
O_BINARY | O_RDONLY)) == -1)
bummer(file_i1[step]);
else
if(read_tga_header(file_i1_handle,&width,
&height,&type,&orient) == -1)
bummer(file_i1[step]);
}
if(file_i2[step][0])
{
if((file_i2_handle = open(file_i2[step],
O_BINARY | O_RDONLY)) == -1)
bummer(file_i2[step]);
else
if(read_tga_header(file_i2_handle,&width,
&height,&type,&orient) == -1)
bummer(file_i2[step]);
}
if(file_o[step][0])
{
if((file_o_handle = open(file_o[step],
O_BINARY | O_WRONLY | O_CREAT | O_TRUNC,
S_IWRITE | S_IREAD)) == -1)
bummer(file_o[step]);
else
if(write_tga_header(file_o_handle,width,
height,orient) == -1)
bummer(file_o[step]);
}
/*.............................................................*/
/* Prepare to read out TARGA file(s). */
/*.............................................................*/
if(orient == 32)
{
jstrt = 0;
jend = height;
jstep = 1;
}
else
{
jstrt = height-1;
jend = -1;
jstep = -1;
}
/*.............................................................*/
/* Do a Quicky Display of the TARGA file in file_i1, */
/* (And remember to reset file pointer !!!) */
/* Only do this where it makes sense (steps 1, 2, and 5). */
/*.............................................................*/
if((step == 1) || (step == 2) || (step == 5))
{
frame();
if(file_i1[step][0])
{
text_update("Displaying the Input File.",252);
for(j=jstrt;j!=jend;j+=jstep)
{
if(read(file_i1_handle,rgb_1,3*width) != 3*width)
bummer(file_i1[step]);
get_dithered_row(width,j,rgb_1,rgb_2);
vsa_raster_line(0,width-1,j,rgb_2);
}
lseek(file_i1_handle,18,SEEK_SET);
}
}
/*.............................................................*/
/* Read out pixels from TARGA file(s) and process them. */
/*.............................................................*/
text_update("Processing, Please Wait.",252);
frame();
for(j=jstrt;j!=jend;j+=jstep)
{
if(file_i1[step][0])
if(read(file_i1_handle,rgb_1,3*width) != 3*width)
bummer(file_i1[step]);
if(file_i2[step][0])
if(read(file_i2_handle,rgb_2,3*width) != 3*width)
bummer(file_i2[step]);
process_step(rgb_1,rgb_2,width,j,step);
if(file_o[step][0])
if(write(file_o_handle,rgb_1,3*width) != 3*width)
bummer(file_o[step]);
}
/*.............................................................*/
/* If a file was opened, close it now. */
/*.............................................................*/
if(file_i1[step][0]) close(file_i1_handle);
if(file_i2[step][0]) close(file_i2_handle);
if( file_o[step][0]) close(file_o_handle);
/*.............................................................*/
/* Here's your chance too get out ... */
/*.............................................................*/
sprintf(text,"Step %d Done. Hit Any Key.",step);
text_update(text,224);
if(getch() == 27)
goto BAIL;
frame();
}
/*.............................................................*/
/* Program is over, return display to standard text mode. */
/*.............................................................*/
BAIL:
vsa_init(0x3);
return;
}
void process_step(unsigned char *rgb_1,unsigned char *rgb_2,
int width,int j,int step)
{
switch(step)
{
case 0:
azure_sky(rgb_1,width,j);
break;
case 1:
wipe_sky(rgb_1,width,j);
break;
case 2:
shrink_city(rgb_1,width,j);
break;
case 3:
merge_city(rgb_1,width,j);
break;
case 4:
merge_azure(rgb_1,rgb_2,width,j);
break;
case 5:
shrink_saucer(rgb_1,width,j);
break;
case 6:
merge_saucer(rgb_1,width,j);
break;
case 7:
add_shadow(rgb_1,width,j);
break;
case 8:
add_beam(rgb_1,width,j);
break;
default: break;
}
return;
} /*.... END process_step .....*/
/*........................ AZURE_SKY ..........................*/
/* This routine generates a blue, blue-green gradient much */
/* like the crisp blue skies of Montana. (Never been there, */
/* seen pictures). (The data is displayed as its generated). */
/*.............................................................*/
void azure_sky(unsigned char *rgb_1,int width,int j)
{
unsigned char array[1024];
int i;
for(i=0;i<width;i++)
{
rgb_1[3*i+2] = 0;
rgb_1[3*i+1] = 64+j/2.53;
rgb_1[3*i+0] = 128+j/3.75;
}
get_dithered_row(width,j,rgb_1,array);
vsa_raster_line(0,width-1,j,array);
return;
} /*.... END azure_sky .....*/
/*......................... WIPE_SKY ..........................*/
/* This routine is customized to work specifically with the */
/* MOUNTAIN.TGA picture. It goes in and zeros out the sky to */
/* prepare MOUNTAIN.TGA for the next step. */
/* This routine makes use of a hue test and a color test */
/* to determine which pixels make up the sky. The hue test */
/* finds similar hues independent of brightness while the */
/* color test finds similar colors in the absolute sense. */
/*.............................................................*/
void wipe_sky(unsigned char *rgb_1,int width,int j)
{
unsigned char array[1024];
int i;
float h_error,c_error;
for(i=0;i<width;i++)
{
h_error = hue_error(rgb_1[3*i+2],rgb_1[3*i+1],
rgb_1[3*i+0],0.62,0.54,0.58);
c_error = color_error(rgb_1[3*i+2],rgb_1[3*i+1],
rgb_1[3*i+0],140,122,131);
if((h_error < 0.03) && (c_error < 17))
{
rgb_1[3*i+2] = 0;
rgb_1[3*i+1] = 0;
rgb_1[3*i+0] = 0;
}
}
get_dithered_row(width,j,rgb_1,array);
vsa_raster_line(0,width-1,j,array);
return;
} /*.... END wipe_sky .....*/
/*......................... SHRINK_CITY .......................*/
/* This routine is customized to work specifically with the */
/* CITY.TGA picture. It extracts the city within a window */
/* and shrinks it by a factor of 3 in x and y. Then the */
/* resulting image is placed in the external 'image' array */
/* and also displayed on the screen. */
/*.............................................................*/
void shrink_city(unsigned char *rgb_1,int width,int j)
{
int i,n,q,red,grn,blu;
unsigned char array[1024];
/*.............................................................*/
/* Put up a gray box where reduced city will be drawn. */
/* Only draw it once, just before city shrinking starts. */
/*.............................................................*/
if(j == 479)
{
vsa_set_color(0x49);
vsa_move_to(242,331);
vsa_rect_fill(356,406);
}
/*.............................................................*/
/* Bail out unless you're within the extract region of the */
/* image and you're on every 3rd row. */
/*.............................................................*/
if((j < 60) || (j > 290))
return;
if((((float)j/3.0)-j/3) != 0)
return;
/*.............................................................*/
/* Extract city within rectangle 115,60 to 460,290 and reduce */
/* size by a factor of 3 by simple undersampling of image and */
/* convert extracted pixels to grayscale. Store in image array*/
/* Then display reduced city in little window. */
/*.............................................................*/
n = ((j-60)/3)*115;
q=j/3+310;
for(i=115;i<460;i+=3)
{
red = rgb_1[3*i+2];
grn = rgb_1[3*i+1];
blu = rgb_1[3*i+0];
image[n] = (red + grn + blu)/3;
rgb_1[i+2] = image[n];
rgb_1[i+1] = image[n];
rgb_1[i+0] = image[n];
n++;
}
get_dithered_row(width,q,rgb_1+115,array);
vsa_raster_line(242,356,q,array);
return;
} /*.... END shrink_city .....*/
/*.......................... MERGE_CITY .......................*/
/* This routine takes the reduced city in the 'image' array */
/* and inserts it into the WIPED.TGA image replacing only */
/* those pixels which are equal to zero. */
/*.............................................................*/
void merge_city(unsigned char *rgb_1,int width,int j)
{
int i,n;
unsigned char array[1024];
/*.............................................................*/
/* Composite the city in the 'image' array with the WIPED */
/* mountain scene within rectangle (523,214) to (637,289). */
/* Also display results. */
/*.............................................................*/
for(i=0;i<width-1;i++)
{
if((j >= 214) && (j <= 289))
if((i>=523) && (i < 637))
if((rgb_1[3*i+2] | rgb_1[3*i+1] | rgb_1[3*i+0]) == 0)
{
n=i-523 + (j-214)*115;
rgb_1[3*i+2] = image[n];
rgb_1[3*i+1] = image[n];
rgb_1[3*i+0] = image[n];
}
}
get_dithered_row(width,j,rgb_1,array);
vsa_raster_line(0,width-1,j,array);
return;
} /*.... END merge_city .....*/
/*.......................... MERGE_AZURE ......................*/
/* This routine takes the azure sky in SKY.TGA and uses its */
/* data to replace all zero value pixels in the previous */
/* image WITHCITY.TGA. */
/*.............................................................*/
void merge_azure(unsigned char *rgb_1,unsigned char *rgb_2,
int width,int j)
{
unsigned char array[1024];
int i;
for(i=0;i<width;i++)
{
if((rgb_1[3*i+2] | rgb_1[3*i+1] | rgb_1[3*i+0]) == 0)
{
rgb_1[3*i+2] = rgb_2[3*i+2];
rgb_1[3*i+1] = rgb_2[3*i+1];
rgb_1[3*i+0] = rgb_2[3*i+0];
}
}
get_dithered_row(width,j,rgb_1,array);
vsa_raster_line(0,width-1,j,array);
return;
} /*.... END merge_azure .....*/
/*......................... SHRINK_SAUCER .....................*/
/* This routine is customized to work specifically with the */
/* SAUCER.TGA picture. It extracts the saucer within a window*/
/* and shrinks it by a factor of 2.5 in x and y. Then the */
/* resulting image is placed in the external 'image' array */
/* and also displayed on the screen. */
/*.............................................................*/
void shrink_saucer(unsigned char *rgb_1,int width,int j)
{
int i,n,p,q,red,grn,blu;
float x;
unsigned char array[1024];
/*.............................................................*/
/* Put up a gray box where reduced saucer will be drawn. */
/* Only draw it once, just before saucer shrinking starts. */
/*.............................................................*/
if(j == 479)
{
vsa_set_color(0x49);
vsa_move_to(235,310);
vsa_rect_fill(414,379);
}
/*.............................................................*/
/* Bail out unless you're within the extract region of the */
/* image and you're on every 2.5th row. */
/*.............................................................*/
if((j < 125) || (j > 298))
return;
if((int)(j/2.5) == (int)((j-1)/2.5))
return;
/*.............................................................*/
/* Extract saucer within rectangle 100,125 to 550,300 and */
/* reduce size by a factor of 2.5 by simple undersampling of */
/* image and convert extracted pixels to grayscale. Store in */
/* 'image' array and also dither and display on screen. */
/*.............................................................*/
n=180*(int)((j-125)/2.5);
p=0;
q=j/2.5+260;
for(x=100;x<550;x+=2.5)
{
i = x+0.5;
red = rgb_1[3*i+2];
grn = rgb_1[3*i+1];
blu = rgb_1[3*i+0];
image[n] = (red + grn + blu)/3;
rgb_1[p+2] = image[n];
rgb_1[p+1] = image[n];
rgb_1[p+0] = image[n];
n++;
p+=3;
}
get_dithered_row(width,q,rgb_1,array);
vsa_raster_line(235,414,q,array);
return;
} /*.... END shrink_saucer .....*/
/*.......................... MERGE_SAUCER .....................*/
/* This routine takes the reduced saucer in the 'image' array */
/* and inserts it into the WITHSKY.TGA image. The replacement*/
/* decision is based on a test of the pixel's blue component */
/* in the WITHSKY.TGA picture. */
/*.............................................................*/
void merge_saucer(unsigned char *rgb_1,int width,int j)
{
int i,n;
unsigned char array[1024];
/*.............................................................*/
/* Composite the saucer in the image array with the modified */
/* mountain scene within the rectangle defined by (203,25) */
/* and (382,94). Use a modified "replace if brighter" test. */
/* Specifically, replace if saucer pixel is greater than 1/3 */
/* of existing pixels blue component. (nothing magical here, */
/* this scheme was found by experimenting). */
/*.............................................................*/
n = (j-25)*180;
for(i=0;i<width-1;i++)
{
if((j >= 25) && (j <= 94))
if((i >= 203) && (i <= 382))
{
if(image[n] >= (rgb_1[3*i+0]/3))
{
rgb_1[3*i+2] = image[n];
rgb_1[3*i+1] = image[n];
rgb_1[3*i+0] = image[n];
}
n++;
}
}
get_dithered_row(width,j,rgb_1,array);
vsa_raster_line(0,width-1,j,array);
return;
} /*.... END merge_saucer .....*/
/*........................ ADD_SHADOW .........................*/
/* This routine generates an ellipse and then composits it */
/* with the WITHSAUC.TGA picture using a subtractive */
/* technique. The ellipse serves as a mask which causes a */
/* 30% reduction of pixel intensity for masked pixels. */
/*.............................................................*/
void add_shadow(unsigned char *rgb_1,int width,int j)
{
int i,n;
unsigned char array[1024];
float scale;
/*.............................................................*/
/* Generate an ellipse mask in the 'image' array once before */
/* getting to overlay region. */
/*.............................................................*/
if(j==479)
ellipse(180,35);
/*.............................................................*/
/* Composite the shadow disk region (75,310) (254,344). */
/*.............................................................*/
n = (j-310)*180;
for(i=0;i<width-1;i++)
{
if((j >= 310) && (j <= 344))
if((i >= 75) && (i <= 254))
{
scale = (255.0 - 0.4*image[n])/255.0;
rgb_1[3*i+2] = rgb_1[3*i+2]*scale;
rgb_1[3*i+1] = rgb_1[3*i+1]*scale;
rgb_1[3*i+0] = rgb_1[3*i+0]*scale;
n++;
}
}
get_dithered_row(width,j,rgb_1,array);
vsa_raster_line(0,width-1,j,array);
return;
} /*.... END add_shadow .....*/
/*........................ ADD_BEAM ...........................*/
/* This routine generates a Transporter Beam (the standard */
/* issue) and composits it with the WITHSHAD.TGA picture */
/* using an additive technique. The beam has a sinusoidal */
/* intensity cross section and is capped with an ellipse. */
/*.............................................................*/
void add_beam(unsigned char *rgb_1,int width,int j)
{
int i,n,red,grn,boost;
unsigned char array[1024];
float taps[40];
/*.............................................................*/
/* Generate an ellipse mask in the 'image' array once before */
/* getting to overlay region. Also precompute the */
/* sinusoidal beam profile. */
/*.............................................................*/
if(j==479)
{
ellipse(40,22);
for(i=0;i<40;i++)
taps[i] = sin(0.0785*(float)i);
}
/*.............................................................*/
/* Use an additive mixing technique to composite the beam */
/* (me up scotty) into the image. Beam fills rectangle with */
/* coordinates (273,88) to (312,320). */
/*.............................................................*/
n = (j-294)*40;
for(i=0;i<width-1;i++)
{
if((j >= 88) && (j <= 304))
if((i >= 273) && (i <= 312))
{
boost = 75.0*taps[i-273];
red = rgb_1[3*i+2] + boost;
grn = rgb_1[3*i+1] + boost;
rgb_1[3*i+2] = min(red,255);
rgb_1[3*i+1] = min(grn,255);
}
/*.... Cap the beam with half of an ellipse. ...*/
if((j >= 305) && (j <= 315))
if((i >= 273) && (i <= 312))
{
boost = (75.0*taps[i-273]*image[n])/255.0;
red = rgb_1[3*i+2] + boost;
grn = rgb_1[3*i+1] + boost;
rgb_1[3*i+2] = min(red,255);
rgb_1[3*i+1] = min(grn,255);
n++;
}
}
get_dithered_row(width,j,rgb_1,array);
vsa_raster_line(0,width-1,j,array);
return;
} /*.... END add_beam .....*/
/*....................... READ_TGA_HEADER ....... 5-17-94 ....*/
/* This routine parses through a TGA header and returns the */
/* file offset in bytes to the first byte of pixel data. */
/* It also returns image width, height, and type (type 2 is the*/
/* uncompressed 24 bit image type). */
/*.............................................................*/
long read_tga_header(int handle, int *width,
int *height, int *type,
int *orientation)
{
unsigned long offset;
unsigned char buff[18];
if(read(handle,buff,18) != 18)
return -1;
offset = 18+buff[0];
*type = buff[2];
*width = *((unsigned *)buff + 6);
*height = *((unsigned *)buff + 7);
*orientation = buff[17];
return offset;
} /*.... END read_tga_header .....*/
/*....................... WRITE_TGA_HEADER ....... 7-5-94 ....*/
/* This routine writes a TGA header: 24 bit true color image */
/*.............................................................*/
int write_tga_header(int handle, int width,int height,
int orientation)
{
int error = 0;
unsigned char buff[18];
buff[0] = 0;
buff[1] = 0;
buff[2] = 2;
buff[3] = 0;
buff[4] = 0;
buff[5] = 0;
buff[6] = 0;
buff[7] = 0;
buff[8] = 0;
*((unsigned *)buff + 4) = 0;
*((unsigned *)buff + 5) = 0;
*((unsigned *)buff + 6) = width;
*((unsigned *)buff + 7) = height;
buff[16] = 24;
buff[17] = orientation;
if(write(handle,buff,18) != 18)
error = -1;
return error;
} /*.... END write_tga_header .....* /
/*.................... GET_DITHERED_ROW ......... 7-15-94 .....*/
/* This routine computes the dithered pixel color for all of */
/* pixels in a row in the array 'rgb' and stores the results */
/* in the array 'pixels'. The row is 'width' wide and starts at*/
/* screen row address 'j'. The 'rgb' array is a 24 bit color */
/* array with every 3 bytes defining a new pixel. The */
/* resulting 'pixels' array defines each pixel as an 8 bit RGB */
/* pixel (one byte per pixel). */
/*.............................................................*/
void get_dithered_row(int width,int j,unsigned char *rgb,
unsigned char *pixels)
{
int i,n,m,q,r,red_lvl,grn_lvl,blu_lvl,size,size_sqr;
int red_boost,grn_boost,blu_boost;
float x,y,frl,fgl,fbl;
size = 8;
size_sqr = 64;
q = 3;
/*.... If FAST_RGB = 1, don't dither, do fast 8 bit RGB. ....*/
if(FAST_RGB)
{
for(i=0;i<width;i++)
{
pixels[i] = (rgb[3*i+2] & 0xe0) +
((rgb[3*i+1] & 0xe0) >> 3) +
(rgb[3*i+0] >> 6);
}
return;
}
y = (float)j/size;
n = (int)(size*(y - (int)y) + 0.5);
for(i=0;i<width;i++)
{
/*.............................................................*/
/* For the pixels screen address i,j, compute pixel address r */
/* within the dither box. Also select dither box q based on */
/* size (size = 1, 2, 4, or 8) (q = 0, 1, 2, or 3). */
/*.............................................................*/
x = (float)i/size;
m = (int)(size*(x - (int)x) + 0.5);
r = m+n*size;
/*.............................................................*/
/* Get the Dark Pixel color, the Light Pixel components, and */
/* the pixel color errors. */
/*.............................................................*/
pixels[i] = crack_rgb(rgb+3*i,&red_boost,&grn_boost,
&blu_boost,&frl,&fgl,&fbl);
/*.............................................................*/
/*Scale the pixel color error values based on dither box size */
/*.............................................................*/
red_lvl = size_sqr*frl;
grn_lvl = size_sqr*fgl;
blu_lvl = size_sqr*fbl;
/*.............................................................*/
/*Test the pixels red, green, and blue error values against the*/
/*thresholds in the dither box. Decide which color to use. */
/*.............................................................*/
if(dither[q][r] <= red_lvl) /*Boost Red*/
pixels[i] = (pixels[i] & 0x1f)+(red_boost<<5);
if(dither[q][r] <= grn_lvl) /*Boost Grn*/
pixels[i] = (pixels[i] & 0xe3)+(grn_boost<<2);
if(dither[q][r] <= blu_lvl) /*Boost Blu*/
pixels[i] = (pixels[i] & 0xfc)+blu_boost;
}
return;
} /*.... END get_dithered_row ....*/
/*.......................... CRACK_RGB ........... 5-27-94 ....*/
/* This routine takes the 24 bit RGB color value in the 'rgb' */
/* array, quantizes it down to an 8 bit color value (3 bit red,*/
/* 3 bit green, and 2 bit blue) and returns this 8 bit */
/* 'base_color' value. It also computes the 8 bit color boost */
/* values '*red_boost', 'grn_boost', and 'blu_boost' which are */
/* used to draw dithered pixels. It also computes the color */
/* error values 'red_lvl', 'grn_lvl', and 'blu_lvl' which */
/* determine when the dither function draws with 'base_color' */
/* and when it draws with 'xxx_boost' color. */
/*.............................................................*/
int crack_rgb(unsigned char *rgb,int *red_boost,int *grn_boost,
int *blu_boost,float *red_lvl,float *grn_lvl,
float *blu_lvl)
{
int base_color,red,grn,blu;
float fred,fgrn,fblu;
fred = rgb[2]/36.6; /*36.6 = (256 shades of red)/(2^3 - 1) */
fgrn = rgb[1]/36.6; /*36.6 = (256 shades of grn)/(2^3 - 1) */
fblu = rgb[0]/85.4; /*85.4 = (256 shades of blu)/(2^2 - 1) */
red = fred;
grn = fgrn;
blu = fblu;
base_color = (red << 5)+(grn << 2)+blu; /*Dark Pixel color */
*red_lvl = fred - red;
*grn_lvl = fgrn - grn;
*blu_lvl = fblu - blu;
*red_boost = red+1; /*This is the Light Pixel color for red */
*grn_boost = grn+1; /*This is the Light Pixel color for grn */
*blu_boost = blu+1; /*This is the Light Pixel color for blu */
return base_color;
} /*.... END crack_rgb .....*/
/*.................... TRUE_COLOR_LUT.C .......... 5-15-94 ....*/
/* This routine generates a 'true color' LUT. An 8 bit index */
/* into the LUT represents 3 bits of RED, 3 bits of GREEN, and */
/* 2 bits of BLUE. The 3 msbs of the 8 bit index are the RED */
/* field, next 3 are GREEN, and the 2 lsbs are the BLUE field. */
/* */
/*.............................................................*/
void true_color_lut(void)
{
int i;
unsigned char color_array[768];
for(i=0;i<256;i++)
{
color_array[3*i+0]= ((i & 0x00e0) >> 5) * 9;
color_array[3*i+1]= ((i & 0x001c) >> 2) * 9;
color_array[3*i+2]= (i & 0x0003) * 21;
}
vsa_write_color_block(0,256,color_array);
return;
} /*..... End true_color_lut .....*/
/*.................... COLOR_MAG .............. 7-15-94 .......*/
/* This routine takes an RGB color defined by 'r', 'g', and */
/* 'b' and returns the absolute magnitude (brightness) of the */
/* color. */
/*.............................................................*/
float color_mag(float r,float g,float b)
{
return sqrt(r*r+g*g+b*b);
} /*..... End color_mag .....*/
/*.................... COLOR_ERROR ............ 7-15-94 .......*/
/* This routine takes two RGB colors defined by 'r0', 'g0', */
/* 'b0' and 'r1', 'g1', 'b1' and returns the distance between */
/* the two colors in RGB color space. */
/*.............................................................*/
float color_error(float r0,float g0,float b0,
float r1,float g1,float b1)
{
float dr,dg,db;
dr = (r0-r1);
dg = (g0-g1);
db = (b0-b1);
return sqrt(dr*dr+dg*dg+db*db);
} /*..... End color_error .....*/
/*.................... HUE_ERROR .............. 7-15-94 .......*/
/* This routine compares the RGB color defined by 'r,g,b' to */
/* the color HUE defined by 'ur,ug,ub' and returns the distance*/
/* between the RGB color and the HUE. The distance ranges */
/* from 0 to square root of 3 (1.73...) */
/* NOTE: 'ur,ug,ub' is a "Unit Vector" and */
/* sqrt(ur*ur + ug*ug + ub*ub) must equal 1.0. */
/*.............................................................*/
float hue_error(float r,float g,float b,
float ur,float ug,float ub)
{
float dr,dg,db,mag;
mag = color_mag(r,g,b);
if(mag == 0) mag = 1.0;
dr = (r/mag-ur);
dg = (g/mag-ug);
db = (b/mag-ub);
return sqrt(dr*dr+dg*dg+db*db);
} /*..... End hue_error .....*/
/*.......................... BUMMER ...........................*/
/* This routine prints a file error message. You give */
/* it the name of the file for the message in 'filename'. */
/*.............................................................*/
void bummer(char *filename)
{
char text[100];
sprintf(text,
"File Access Error! Filename = '%s'",filename);
vsa_write_string(0,YResolution-2*YCharSize,224,text);
vsa_write_string(0,YResolution-1*YCharSize,224,
"Hit Any Key ...");
getch();
vsa_init(3);
exit(1);
} /*..... End bummer .....*/
/*......................... TEXT_UPDATE .......................*/
/* This routine prints the text string in 'text' out to the */
/* screen in 'color'. It does this at the bottom center of a */
/* 640 x 480 screen by first clearing out the last printed */
/* message. */
/*.............................................................*/
void text_update(char *text,int color)
{
vsa_set_text_scale(1.2,1.2);
vsa_set_color(0);
vsa_move_to(200,475-YCharSize-1);
vsa_rect_fill(460,475);
vsa_write_string(205,475-YCharSize,color,text);
return;
} /*..... End text_update .....*/
/*............................. FRAME .........................*/
/* This routine draws a frame around the 640 x 480 screen. */
/* The reason I do this is so that you can tell when an image */
/* is being redrawn (the frame slowly gets eaten up). */
/*.............................................................*/
void frame(void)
{
vsa_set_color(255);
vsa_move_to(0,0);
vsa_rect(639,479);
vsa_set_color(0);
vsa_move_to(1,1);
vsa_rect(638,478);
vsa_set_color(255);
vsa_move_to(2,2);
vsa_rect(637,477);
vsa_set_color(0);
vsa_move_to(3,3);
vsa_rect(636,476);
return;
} /*..... End frame .....*/
/*......................... ELLIPSE .............. 7-22-94 ....*/
/* This routine generates a filled ellipse mask into the */
/* global 'image array. The ellipse has width of 'dx' and */
/* height of 'dy'. The equation for this ellipse is: */
/* */
/* x^2 + y^2 */
/* -------- -------- = 1 */
/* (dx/2)^2 (dy/2)^2 */
/* */
/* The 'image' array values are 0 outside of the ellipse and */
/* 255 inside the ellipse. The ellipse has a soft edge with */
/* 'image' values between 0 and 255. The soft edge is */
/* achieved by a 3x3 pixel averaging operation via the */
/* 'soft_edge' function. */
/* */
/* NOTE: The 'image' array must be large enough to hold all of */
/* this data (image will be dx wide and dy high). */
/*.............................................................*/
void ellipse(int dx,int dy)
{
int i,j,m,n;
float rx,ry;
/*.............................................................*/
/* Clear out the image array before writing in ellipse mask. */
/*.............................................................*/
for(n=0;n<dy;n++)
for(m=0;m<dx;m++)
image[m+n*dx] = 0;
/*.............................................................*/
/* Now compute ellipse and draw its mask into image array. */
/*.............................................................*/
rx = (dx-1)/2.0;
ry = (dy-1)/2.0;
for(j=-ry ; j<=+ry ; j++)
{
i = sqrt(rx*rx*(1 - (j*j)/(ry*ry)));
for(m=-i;m<=i;m++)
{
n = m+rx+(j+(int)ry)*dx;
image[n] = 255;
}
}
soft_edge(image,dx,dy);
return;
} /*..... End ellipse .....*/
void introduction(void)
{
printf("This program goes through the evolution of mild\n");
printf("mannered MOUNTAIN.TGA to the ultimate UFO sighting\n");
printf("UFO.TGA. Before you run this program, You must\n");
printf("have the following three files in the current\n");
printf("directory:\n");
printf(" MOUNTAIN.TGA\n");
printf(" CITY.TGA\n");
printf(" SAUCER.TGA\n");
printf("\n");
printf("Furthermore, you need an additional 7 Mbytes\n");
printf("of hard disk space available since the following\n");
printf("intermediate TARGA image files are created:\n");
printf("\n");
printf(" SKY.TGA\n");
printf(" WIPED.TGA\n");
printf(" WITHCITY.TGA\n");
printf(" WITHSKY.TGA\n");
printf(" WITHSAUC.TGA\n");
printf(" WITHSHAD.TGA\n");
printf(" UFO.TGA (This is the final image)\n");
printf("\n");
printf("Hit any key to continue, ESC to quit.\n");
if(getch() == 27)
exit(1);
return;
}
void soft_edge(unsigned char *image,int width,int height)
{
int i,j,m,n,q,x,y;
/*.............................................................*/
/* First clear out the temporary array. */
/*.............................................................*/
for(i=0;i<width*height;i++)
big_image[i] = 0;
/*.............................................................*/
/* Now, for each pixel in 'image' array, do a 3x3 pixel */
/* average. */
/*.............................................................*/
for(j=0;j<height;j++)
for(i=0;i<width;i++)
{
q = i+j*width;
for(n=0;n<3;n++)
for(m=0;m<3;m++)
{
x = i+m-1;
y = j+n-1;
if((y >= 0) && (y < height))
if((x >= 0) && (x < width))
big_image[q] += image[x+y*width];
}
big_image[q] = big_image[q]/9;
}
/*.............................................................*/
/* Finally, transfer results back to the 'image' array. */
/*.............................................................*/
for(i=0;i<width*height;i++)
image[i] = big_image[i];
return;
}